package par

import (
	"testing"

	"gitcode.com/deyiyangyang/gascheme/ast"
	"gitcode.com/deyiyangyang/gascheme/lex"
)

func TestIntegerLiteralParsing(t *testing.T) {
	input := "42"

	l := lex.NewLexer(input)
	p := NewParser(l)

	expr, err := p.ParseExpression()
	if err != nil {
		t.Fatalf("Error parsing integer literal: %s", err)
	}

	integer, ok := expr.(*ast.IntegerLiteral)
	if !ok {
		t.Fatalf("expr is not *ast.IntegerLiteral. got=%T", expr)
	}

	if integer.Value != 42 {
		t.Errorf("integer.Value wrong. got=%d, want=%d", integer.Value, 42)
	}
}

func TestRationalLiteralParsing(t *testing.T) {
	input := "3/4"

	l := lex.NewLexer(input)
	p := NewParser(l)

	expr, err := p.ParseExpression()
	if err != nil {
		t.Fatalf("Error parsing rational literal: %s", err)
	}

	rational, ok := expr.(*ast.RationalLiteral)
	if !ok {
		t.Fatalf("expr is not *ast.RationalLiteral. got=%T", expr)
	}

	if rational.Numerator != 3 || rational.Denominator != 4 {
		t.Errorf("rational.Value wrong. got=%d/%d, want=3/4", rational.Numerator, rational.Denominator)
	}
}

func TestRealLiteralParsing(t *testing.T) {
	input := "3.14"

	l := lex.NewLexer(input)
	p := NewParser(l)

	expr, err := p.ParseExpression()
	if err != nil {
		t.Fatalf("Error parsing real literal: %s", err)
	}

	real, ok := expr.(*ast.RealLiteral)
	if !ok {
		t.Fatalf("expr is not *ast.RealLiteral. got=%T", expr)
	}

	if real.Value != 3.14 {
		t.Errorf("real.Value wrong. got=%f, want=%f", real.Value, 3.14)
	}
}

func TestListExpressionParsing(t *testing.T) {
	input := "(1 2 3)"

	l := lex.NewLexer(input)
	p := NewParser(l)

	expr, err := p.ParseExpression()
	if err != nil {
		t.Fatalf("Error parsing list expression: %s", err)
	}

	list, ok := expr.(*ast.ListExpression)
	if !ok {
		t.Fatalf("expr is not *ast.ListExpression. got=%T", expr)
	}

	if len(list.Elements) != 3 {
		t.Errorf("list has wrong number of elements. got=%d, want=%d", len(list.Elements), 3)
	}

	// Verify each element is an integer
	for i, val := range []int64{1, 2, 3} {
		integer, ok := list.Elements[i].(*ast.IntegerLiteral)
		if !ok {
			t.Fatalf("element %d is not *ast.IntegerLiteral. got=%T", i, list.Elements[i])
		}
		if integer.Value != val {
			t.Errorf("element %d has wrong value. got=%d, want=%d", i, integer.Value, val)
		}
	}
}

func TestAdditionParsing(t *testing.T) {
	input := "(+ 1 2)"

	l := lex.NewLexer(input)
	p := NewParser(l)

	expr, err := p.ParseExpression()
	if err != nil {
		t.Fatalf("Error parsing addition expression: %s", err)
	}

	list, ok := expr.(*ast.ListExpression)
	if !ok {
		t.Fatalf("expr is not *ast.ListExpression. got=%T", expr)
	}

	if len(list.Elements) != 3 {
		t.Errorf("addition list has wrong number of elements. got=%d, want=%d", len(list.Elements), 3)
	}

	// First element should be the + symbol
	op, ok := list.Elements[0].(*ast.SymbolLiteral)
	if !ok {
		t.Fatalf("first element is not *ast.SymbolLiteral. got=%T", list.Elements[0])
	}
	if op.Value != "+" {
		t.Errorf("operator is wrong. got=%s, want=%s", op.Value, "+")
	}

	// Verify operands
	for i, val := range []int64{1, 2} {
		integer, ok := list.Elements[i+1].(*ast.IntegerLiteral)
		if !ok {
			t.Fatalf("element %d is not *ast.IntegerLiteral. got=%T", i+1, list.Elements[i+1])
		}
		if integer.Value != val {
			t.Errorf("element %d has wrong value. got=%d, want=%d", i+1, integer.Value, val)
		}
	}
}

func TestComplexExpressionParsing(t *testing.T) {
	input := "(+ (* 2 3) (- 5 1))"

	l := lex.NewLexer(input)
	p := NewParser(l)

	expr, err := p.ParseExpression()
	if err != nil {
		t.Fatalf("Error parsing complex expression: %s", err)
	}

	list, ok := expr.(*ast.ListExpression)
	if !ok {
		t.Fatalf("expr is not *ast.ListExpression. got=%T", expr)
	}

	if len(list.Elements) != 3 {
		t.Errorf("complex list has wrong number of elements. got=%d, want=%d", len(list.Elements), 3)
	}

	// First element should be the + symbol
	op, ok := list.Elements[0].(*ast.SymbolLiteral)
	if !ok {
		t.Fatalf("first element is not *ast.SymbolLiteral. got=%T", list.Elements[0])
	}
	if op.Value != "+" {
		t.Errorf("operator is wrong. got=%s, want=%s", op.Value, "+")
	}

	// Verify sub-expressions
	multExpr, ok := list.Elements[1].(*ast.ListExpression)
	if !ok {
		t.Fatalf("second element is not *ast.ListExpression. got=%T", list.Elements[1])
	}

	subExpr, ok := list.Elements[2].(*ast.ListExpression)
	if !ok {
		t.Fatalf("third element is not *ast.ListExpression. got=%T", list.Elements[2])
	}

	// Check multiplication expression
	if len(multExpr.Elements) != 3 {
		t.Errorf("malformed multiplication expression: %d elements", len(multExpr.Elements))
	} else {
		multOp, ok := multExpr.Elements[0].(*ast.SymbolLiteral)
		if !ok {
			t.Fatalf("multiplication operator is not *ast.SymbolLiteral. got=%T", multExpr.Elements[0])
		}
		if multOp.Value != "*" {
			t.Errorf("multiplication operator is wrong. got=%s, want=%s", multOp.Value, "*")
		}
	}

	// Check subtraction expression
	if len(subExpr.Elements) != 3 {
		t.Errorf("malformed subtraction expression: %d elements", len(subExpr.Elements))
	} else {
		subOp, ok := subExpr.Elements[0].(*ast.SymbolLiteral)
		if !ok {
			t.Fatalf("subtraction operator is not *ast.SymbolLiteral. got=%T", subExpr.Elements[0])
		}
		if subOp.Value != "-" {
			t.Errorf("subtraction operator is wrong. got=%s, want=%s", subOp.Value, "-")
		}
	}
}

func TestDivisionParsing(t *testing.T) {
	input := "(/ 6 3)"

	l := lex.NewLexer(input)
	p := NewParser(l)

	expr, err := p.ParseExpression()
	if err != nil {
		t.Fatalf("Error parsing division expression: %s", err)
	}

	list, ok := expr.(*ast.ListExpression)
	if !ok {
		t.Fatalf("expr is not *ast.ListExpression. got=%T", expr)
	}

	if len(list.Elements) != 3 {
		t.Errorf("division list has wrong number of elements. got=%d, want=%d", len(list.Elements), 3)
	}

	// First element should be the / symbol
	op, ok := list.Elements[0].(*ast.SymbolLiteral)
	if !ok {
		t.Fatalf("first element is not *ast.SymbolLiteral. got=%T", list.Elements[0])
	}
	if op.Value != "/" {
		t.Errorf("operator is wrong. got=%s, want=%s", op.Value, "/")
	}
}

func TestRationalInExpressionParsing(t *testing.T) {
	input := "(+ 1/2 3/4)"

	l := lex.NewLexer(input)
	p := NewParser(l)

	expr, err := p.ParseExpression()
	if err != nil {
		t.Fatalf("Error parsing expression with rational numbers: %s", err)
	}

	list, ok := expr.(*ast.ListExpression)
	if !ok {
		t.Fatalf("expr is not *ast.ListExpression. got=%T", expr)
	}

	if len(list.Elements) != 3 {
		t.Errorf("list has wrong number of elements. got=%d, want=%d", len(list.Elements), 3)
	}

	// First element should be the + symbol
	op, ok := list.Elements[0].(*ast.SymbolLiteral)
	if !ok {
		t.Fatalf("first element is not *ast.SymbolLiteral. got=%T", list.Elements[0])
	}
	if op.Value != "+" {
		t.Errorf("operator is wrong. got=%s, want=%s", op.Value, "+")
	}

	// Verify rational operands
	rational1, ok := list.Elements[1].(*ast.RationalLiteral)
	if !ok {
		t.Fatalf("element 1 is not *ast.RationalLiteral. got=%T", list.Elements[1])
	}
	if rational1.Numerator != 1 || rational1.Denominator != 2 {
		t.Errorf("element 1 has wrong value. got=%d/%d, want=1/2", rational1.Numerator, rational1.Denominator)
	}

	rational2, ok := list.Elements[2].(*ast.RationalLiteral)
	if !ok {
		t.Fatalf("element 2 is not *ast.RationalLiteral. got=%T", list.Elements[2])
	}
	if rational2.Numerator != 3 || rational2.Denominator != 4 {
		t.Errorf("element 2 has wrong value. got=%d/%d, want=3/4", rational2.Numerator, rational2.Denominator)
	}
}

func TestRealInExpressionParsing(t *testing.T) {
	input := "(+ 1.5 2.5)"

	l := lex.NewLexer(input)
	p := NewParser(l)

	expr, err := p.ParseExpression()
	if err != nil {
		t.Fatalf("Error parsing expression with real numbers: %s", err)
	}

	list, ok := expr.(*ast.ListExpression)
	if !ok {
		t.Fatalf("expr is not *ast.ListExpression. got=%T", expr)
	}

	if len(list.Elements) != 3 {
		t.Errorf("list has wrong number of elements. got=%d, want=%d", len(list.Elements), 3)
	}

	// First element should be the + symbol
	op, ok := list.Elements[0].(*ast.SymbolLiteral)
	if !ok {
		t.Fatalf("first element is not *ast.SymbolLiteral. got=%T", list.Elements[0])
	}
	if op.Value != "+" {
		t.Errorf("operator is wrong. got=%s, want=%s", op.Value, "+")
	}

	// Verify real operands
	real1, ok := list.Elements[1].(*ast.RealLiteral)
	if !ok {
		t.Fatalf("element 1 is not *ast.RealLiteral. got=%T", list.Elements[1])
	}
	if real1.Value != 1.5 {
		t.Errorf("element 1 has wrong value. got=%f, want=%f", real1.Value, 1.5)
	}

	real2, ok := list.Elements[2].(*ast.RealLiteral)
	if !ok {
		t.Fatalf("element 2 is not *ast.RealLiteral. got=%T", list.Elements[2])
	}
	if real2.Value != 2.5 {
		t.Errorf("element 2 has wrong value. got=%f, want=%f", real2.Value, 2.5)
	}
}

func TestMixedNumberTypesParsing(t *testing.T) {
	input := "(+ 1 1.5 3/4)"

	l := lex.NewLexer(input)
	p := NewParser(l)

	expr, err := p.ParseExpression()
	if err != nil {
		t.Fatalf("Error parsing expression with mixed number types: %s", err)
	}

	list, ok := expr.(*ast.ListExpression)
	if !ok {
		t.Fatalf("expr is not *ast.ListExpression. got=%T", expr)
	}

	if len(list.Elements) != 4 {
		t.Errorf("list has wrong number of elements. got=%d, want=%d", len(list.Elements), 4)
	}

	// First element should be the + symbol
	op, ok := list.Elements[0].(*ast.SymbolLiteral)
	if !ok {
		t.Fatalf("first element is not *ast.SymbolLiteral. got=%T", list.Elements[0])
	}
	if op.Value != "+" {
		t.Errorf("operator is wrong. got=%s, want=%s", op.Value, "+")
	}

	// Verify operands of different types
	integer, ok := list.Elements[1].(*ast.IntegerLiteral)
	if !ok {
		t.Fatalf("element 1 is not *ast.IntegerLiteral. got=%T", list.Elements[1])
	}
	if integer.Value != 1 {
		t.Errorf("element 1 has wrong value. got=%d, want=%d", integer.Value, 1)
	}

	real, ok := list.Elements[2].(*ast.RealLiteral)
	if !ok {
		t.Fatalf("element 2 is not *ast.RealLiteral. got=%T", list.Elements[2])
	}
	if real.Value != 1.5 {
		t.Errorf("element 2 has wrong value. got=%f, want=%f", real.Value, 1.5)
	}

	rational, ok := list.Elements[3].(*ast.RationalLiteral)
	if !ok {
		t.Fatalf("element 3 is not *ast.RationalLiteral. got=%T", list.Elements[3])
	}
	if rational.Numerator != 3 || rational.Denominator != 4 {
		t.Errorf("element 3 has wrong value. got=%d/%d, want=3/4", rational.Numerator, rational.Denominator)
	}
}

func TestParse001(t *testing.T) {
	input := "1 2"

	l := lex.NewLexer(input)
	p := NewParser(l)

	exps, err := p.Parse()
	if err != nil {
		t.Fatalf("parse error: %s", err)
	}
	if len(exps) != 2 {
		t.Fatalf("wrong number of expressions. got=%d, want=2", len(exps))
	}
}
